#ifndef _GUIGANTRY_H_
#define _GUIGANTRY_H_

#include <iostream>
#include <vector>
#include <time.h>
using namespace std;

#include "GUIBase.h"
#include "Bin.h"
#include "GUIFeeder.h"
#include "Enums.h"

#include <qpainter.h>
#include <qpoint.h>
#include "GantryAgent.h"
#include "Structs.h"
//#include "GantryAgent.h"

class GUIFeeder;
class GantryAgent;

#define GANTRY_IDLE_X 400
#define GANTRY_IDLE_Y 550

#define GANTRY_MOVEMENT_SPEED 15
#define GANTRY_ROTATION_SPEED 5
#define GANTRY_VERT_SPEED 0.03

#define GANTRY_EXPLODE_MOVEMENT_SPEED_MIN 10
#define GANTRY_EXPLODE_ROTATION_SPEED_MIN 5
#define GANTRY_EXPLODE_VERT_SPEED_MIN 0.02

#define GANTRY_EXPLODE_MOVEMENT_SPEED_MAX 30
#define GANTRY_EXPLODE_ROTATION_SPEED_MAX 15
#define GANTRY_EXPLODE_VERT_SPEED_MAX 0.04

enum GantryState
{
	GantryGoingIdle,			// Moving to idle position.
	GantryIdle,					// Idling (not moving, ready to be told to do something)

	/**
	 * DoGUIGoToFeeder
	 */
	GantryPickingUpFullBin,		// Moving to pick up bin.
	GantryMovingToFeeder,		// Has bin, moving to feeder to dump it in.
	GantryMovingBinToPurgeArea,	// Put the bin behind the feeder so when it's purged it goes into the bin.
	GantryDroppingOffEmptyBin,	// Put bin back if there's already a bin in the purge area.

	/**
	 * DoGUIReplaceBin
	 */
	GantryGettingEmptyBin,		// Moving to pick up empty bin.
	GantryFillingEmptyBin,		// Moving off-screen to put parts in bin.
	GantryDroppingOffNewBin,	// Moving back to where the empty bin was picked up.
};

enum GantryVerticalState
{
	GantryStable,
	GantryDropping,
	GantryRising,
};

class GUIGantry : public GUIBase
{
private:
	GantryAgent* gantryAgent;

	GantryState state; // gantry state
	GantryVerticalState vertState;
	bool hasBin;
	bool dropAndPickUpBin;
	bool dropAndLetGoOfBin;
	
	bool exploding;

	int currentBinNum; // The index of the bin in the array that the gantry is working with.
	int currentFeederNum; // The index of the feeder that the bin will be dumped in if in that process.
	int currentLane; //GRAHAM HAD TO ADD THIS
	Bin* currentBinRef; // A reference to the bin (derived from currentBinNum)
	GUIFeeder* currentFeederRef; // ^^
	PartType newBinType; // what kind of parts should be in the bin thats being replaced.

protected:
	vector<Bin*> bins; // List of bin references in the factory.
	vector<GUIFeeder*> feeders; // List of feeder references in the factory.

public:
	GUIGantry(int startX, int startY, QGraphicsScene* = 0);

	static QPointF GetBinLocation(int); // Defines the location of all 8 bins.

	void GiveBinList(vector<Bin*>); // Setter for the bin list.
	Bin* GetBinRef(int); // Get a reference to a bin given the index.

	void GiveFeederList(vector<GUIFeeder*>); // ^^
	GUIFeeder* GetFeederRef(int);

	void DoBreak();
	void DoFix();
	
	void DoExplode();

	// Actions, called by GantryAgent.
	void DoGUIMoveToFeeder(int binNumber, int feederNumber,bool topLane);
	void DoGUIReplaceBin(PartType, int);
	void DoGoIdle();

	bool isExploding() { return exploding; }
	
	void doneMoving(); // Called by the GUIBase when gantry finishes moving.
	void doneScaling(); // ^^ when done scaling.
	void doneRotating(); // ^^
	void advance(int phase);

	void setAgent(GantryAgent* feed); // Setter for a reference to my agent.

private:
	void MoveToBinLocation(int binNumber); // Move to the location of the bin number.
	void DropDown(bool pickUpBin, bool letGoOfBin); // 1/0 to pick up bin, 0/1 to drop off a bin, 0/0 to do neither, 1/1 is invalid.
	void PullUp();
	void LatchOntoBin();
	void UnlatchFromBin();
	void ResumeNormative();
	
	void StopExploding();

	// Private methods for completing different parts of a process, sets gantry state as well.
	void PickUpFullBin();
	void GoToFeeder();
	void DumpBinIntoFeeder();
	void PutBinInPurgeArea();
	void DropOffEmptyBin();
	void GetEmptyBin();
	void FillEmptyBin();
	void FillBinWithParts();
	void DropOffNewBin();

};

#endif
